﻿using System;
using System.Collections.Generic;

namespace Gmantis.Controls.DataGrid
{
    public sealed class DataGridCellsRange
    {
        // Methods
        public DataGridCellsRange(DataGridCell cell)
            : this(cell, cell)
        {
        }

        public DataGridCellsRange(DataGridCellsRange range)
        {
            if (!range.IsValid)
            {
                throw new ArgumentException("The specified range is not valid");
            }
            this.Model = range.Model;
            this.TopLeftCell = range.TopLeftCell;
            this.BottomRightCell = range.BottomRightCell;
        }

        public DataGridCellsRange(DataGridColumn column)
        {
            this.Model = column.DataGrid.Model;
            this.TopLeftCell = this.Model.GetCell(this.Model.Rows[0], column);
            this.BottomRightCell = this.Model.GetCell(this.Model.Rows[this.Model.Rows.Count - 1], column);
        }

        public DataGridCellsRange(DataGridRow row)
        {
            this.Model = row.Model;
            DataGridColumn firstVisibleColumn = this.Model.Columns.GetFirstVisibleColumn();
            DataGridColumn lastVisibleColumn = this.Model.Columns.GetLastVisibleColumn();
            this.TopLeftCell = this.Model.GetCell(row, firstVisibleColumn);
            this.BottomRightCell = this.Model.GetCell(row, lastVisibleColumn);
        }

        public DataGridCellsRange(DataGridCell topLeftCell, DataGridCell bottomRightCell)
        {
            if ((topLeftCell == null) || (bottomRightCell == null))
            {
                throw new ArgumentException("Top-left and bottom-right cells can not be null.");
            }
            if ((topLeftCell.DataGrid == null) || (bottomRightCell.DataGrid == null))
            {
                throw new ArgumentException("Both cells must have a data grid assigned.");
            }
            if (topLeftCell.DataGrid != bottomRightCell.DataGrid)
            {
                throw new ArgumentException("Both cells must belong to the same data grid.");
            }
            if (topLeftCell.Column.DisplayIndex > bottomRightCell.Column.DisplayIndex)
            {
                throw new ArgumentException("Top-left cell column index must be less than bottom-right cell column index.");
            }
            if (topLeftCell.Row.Index > bottomRightCell.Row.Index)
            {
                throw new ArgumentException("Top-left cell row index must be less than bottom-right cell row index.");
            }
            this.Model = topLeftCell.DataGrid.Model;
            this.TopLeftCell = topLeftCell;
            this.BottomRightCell = bottomRightCell;
        }

        public DataGridCellsRange(DataGridColumn leftColumn, DataGridColumn rightColumn)
        {
            if ((leftColumn.DataGrid == null) || (rightColumn.DataGrid == null))
            {
                throw new ArgumentException("Both columns must have a data grid assigned.");
            }
            if (leftColumn.DataGrid != rightColumn.DataGrid)
            {
                throw new ArgumentException("Both columns must belong to the same data grid.");
            }
            this.Model = leftColumn.DataGrid.Model;
            this.TopLeftCell = this.Model.GetCell(this.Model.Rows[0], leftColumn);
            this.BottomRightCell = this.Model.GetCell(this.Model.Rows[this.Model.Rows.Count - 1], rightColumn);
        }

        public DataGridCellsRange(DataGridRow topRow, DataGridRow bottomRow)
        {
            if ((topRow.DataGrid == null) || (bottomRow.DataGrid == null))
            {
                throw new ArgumentException("Both rows must have a data grid assigned.");
            }
            if (topRow.DataGrid != bottomRow.DataGrid)
            {
                throw new ArgumentException("Both rows must belong to the same data grid.");
            }
            this.Model = topRow.DataGrid.Model;
            this.TopLeftCell = this.Model.GetCell(topRow, this.Model.Columns.OrderedColumns[0]);
            this.BottomRightCell = this.Model.GetCell(bottomRow, this.Model.Columns.OrderedColumns[this.Model.Columns.OrderedColumns.Length - 1]);
        }

        public bool Contains(DataGridCell cell)
        {
            if (!this.IsValid)
            {
                return false;
            }
            int index = cell.Row.Index;
            int displayIndex = cell.Column.DisplayIndex;
            return ((((index >= this.TopLeftCell.Row.Index) && (index <= this.BottomRightCell.Row.Index)) && (displayIndex >= this.TopLeftCell.Column.DisplayIndex)) && (displayIndex <= this.BottomRightCell.Column.DisplayIndex));
        }

        public bool Contains(DataGridCellsRange range)
        {
            if (!this.IsValid || !range.IsValid)
            {
                return false;
            }
            int index = this.TopLeftCell.Row.Index;
            int num2 = this.BottomRightCell.Row.Index;
            int num3 = range.TopLeftCell.Row.Index;
            int num4 = range.BottomRightCell.Row.Index;
            int displayIndex = this.TopLeftCell.Column.DisplayIndex;
            int num6 = this.BottomRightCell.Column.DisplayIndex;
            int num7 = range.TopLeftCell.Column.DisplayIndex;
            int num8 = range.BottomRightCell.Column.DisplayIndex;
            return ((((index <= num3) && (num2 >= num4)) && (displayIndex <= num7)) && (num6 >= num8));
        }

        public bool Contains(DataGridColumn column)
        {
            if (!this.IsValid)
            {
                return false;
            }
            int displayIndex = column.DisplayIndex;
            return ((((this.TopLeftCell.Row.Index == 0) && (this.BottomRightCell.Row.Index == (this.Model.Rows.Count - 1))) && (this.TopLeftCell.Column.DisplayIndex <= displayIndex)) && (this.BottomRightCell.Column.DisplayIndex >= displayIndex));
        }

        public bool Contains(DataGridRow row)
        {
            if (!this.IsValid)
            {
                return false;
            }
            int index = row.Index;
            return ((((this.TopLeftCell.Column.DisplayIndex == 0) && (this.BottomRightCell.Column.DisplayIndex == (this.Model.Columns.Count - 1))) && (this.TopLeftCell.Row.Index <= index)) && (this.BottomRightCell.Row.Index >= index));
        }

        public override bool Equals(object obj)
        {
            return (this == (obj as DataGridCellsRange));
        }

        public override int GetHashCode()
        {
            return (this.TopLeftCell.GetHashCode() ^ this.BottomRightCell.GetHashCode());
        }

        public bool Intersects(DataGridCellsRange range)
        {
            if (!this.IsValid || !range.IsValid)
            {
                return false;
            }
            int index = this.TopLeftCell.Row.Index;
            int num2 = this.BottomRightCell.Row.Index;
            int num3 = range.TopLeftCell.Row.Index;
            if ((range.BottomRightCell.Row.Index < index) || (num2 < num3))
            {
                return false;
            }
            int displayIndex = this.TopLeftCell.Column.DisplayIndex;
            int num6 = this.BottomRightCell.Column.DisplayIndex;
            int num7 = range.TopLeftCell.Column.DisplayIndex;
            return ((range.BottomRightCell.Column.DisplayIndex >= displayIndex) && (num6 >= num7));
        }

        public bool IsSingleCell()
        {
            return ((this.IsValid && (this.TopLeftCell.Column == this.BottomRightCell.Column)) && (this.TopLeftCell.Row == this.BottomRightCell.Row));
        }

        public bool IsSingleColumn()
        {
            return (((this.IsValid && (this.TopLeftCell.Column == this.BottomRightCell.Column)) && (this.TopLeftCell.Row.Index == 0)) && (this.BottomRightCell.Row.Index == (this.Model.Rows.Count - 1)));
        }

        public bool IsSingleRow()
        {
            return (((this.IsValid && (this.TopLeftCell.Row == this.BottomRightCell.Row)) && (this.TopLeftCell.Column.DisplayIndex == 0)) && (this.BottomRightCell.Column.DisplayIndex == (this.Model.Columns.Count - 1)));
        }

        public static bool operator ==(DataGridCellsRange obj, DataGridCellsRange obj2)
        {
            if ((obj != null) || (obj2 != null))
            {
                if ((obj == null) || (obj2 == null))
                {
                    return false;
                }
                if (obj.TopLeftCell != obj2.TopLeftCell)
                {
                    return false;
                }
                if (obj.BottomRightCell != obj2.BottomRightCell)
                {
                    return false;
                }
            }
            return true;
        }

        public static bool operator !=(DataGridCellsRange obj, DataGridCellsRange obj2)
        {
            return !(obj == obj2);
        }

        public DataGridCellsRange[] Subtract(DataGridCellsRange range)
        {
            if ((this.IsValid && range.IsValid) && this.Intersects(range))
            {
                DataGridCell topLeftCell = this.TopLeftCell;
                DataGridCell bottomRightCell = this.BottomRightCell;
                DataGridCell cell3 = range.TopLeftCell;
                DataGridCell cell4 = range.BottomRightCell;
                int index = topLeftCell.Row.Index;
                int num2 = bottomRightCell.Row.Index;
                int num3 = cell3.Row.Index;
                int num4 = cell4.Row.Index;
                List<DataGridCellsRange> list = new List<DataGridCellsRange>();
                if (index < num3)
                {
                    list.Add(new DataGridCellsRange(topLeftCell, this.Model.GetCell(this.Model.Rows[num3 - 1], bottomRightCell.Column)));
                    topLeftCell = this.Model.GetCell(cell3.Row, topLeftCell.Column);
                }
                if (num2 > num4)
                {
                    list.Add(new DataGridCellsRange(this.Model.GetCell(this.Model.Rows[num4 + 1], topLeftCell.Column), bottomRightCell));
                    bottomRightCell = this.Model.GetCell(cell4.Row, bottomRightCell.Column);
                }
                int displayIndex = topLeftCell.Column.DisplayIndex;
                int num6 = bottomRightCell.Column.DisplayIndex;
                int num7 = cell3.Column.DisplayIndex;
                int num8 = cell4.Column.DisplayIndex;
                DataGridColumn[] orderedColumns = this.Model.Columns.OrderedColumns;
                if (displayIndex >= num7)
                {
                    if (num6 > num8)
                    {
                        list.Add(new DataGridCellsRange(this.Model.GetCell(topLeftCell.Row, orderedColumns[num8 + 1]), bottomRightCell));
                    }
                }
                else if (num6 <= num8)
                {
                    list.Add(new DataGridCellsRange(topLeftCell, this.Model.GetCell(bottomRightCell.Row, orderedColumns[num7 - 1])));
                }
                else
                {
                    list.Add(new DataGridCellsRange(topLeftCell, this.Model.GetCell(bottomRightCell.Row, orderedColumns[num7 - 1])));
                    list.Add(new DataGridCellsRange(this.Model.GetCell(topLeftCell.Row, orderedColumns[num8 + 1]), bottomRightCell));
                }
                return list.ToArray();
            }
            return new DataGridCellsRange[] { new DataGridCellsRange(this) };
        }

        public override string ToString()
        {
            return string.Format("({0},{1})->({2},{3})", new object[] { this.TopLeftCell.Row.Index, this.TopLeftCell.Column.DisplayIndex, this.BottomRightCell.Row.Index, this.BottomRightCell.Column.DisplayIndex });
        }

        // Properties
        public DataGridCell BottomRightCell { get; private set; }

        public IEnumerable<DataGridColumn> Columns
        {
            get
            {
                int displayIndex = this.TopLeftCell.Column.DisplayIndex;
                while (true)
                {
                    if (!this.IsValid || (displayIndex > this.BottomRightCell.Column.DisplayIndex))
                    {
                        yield break;
                    }
                    yield return this.Model.Columns.OrderedColumns[displayIndex];
                    displayIndex++;
                }
            }
        }

        public bool IsValid
        {
            get
            {
                return ((this.TopLeftCell.DataGrid != null) && (this.BottomRightCell.DataGrid != null));
            }
        }

        private DataGridModel Model { get; set; }

        public IEnumerable<DataGridRow> Rows
        {
            get
            {
                int index = this.TopLeftCell.Row.Index;
                while (true)
                {
                    if (!this.IsValid || (index > this.BottomRightCell.Row.Index))
                    {
                        yield break;
                    }
                    yield return this.Model.Rows[index];
                    index++;
                }
            }
        }

        public DataGridCell TopLeftCell { get; private set; }
    }
}
